
/**
 ********************************  STM32F10x  *********************************
 * @文件名称： bl0939.c
 * @作者名称： GJ
 * @摘要简述： 贝岭计量芯片BL0939驱动
 ******************************************************************************/
#include <string.h>
#include "bl0939.h"
#include "../spi/spi.h"
#include "../utils/utils.h"
#include "../flash/flash.h"

RN_SEND RnSend = {0}; // 发送结构体对象
RN_RECE RnRece = {0}; // 接收结构体对象
Elect_StructDef BL0939_Elect;
u32 Energy_kwh_A_save = 0;

TwoByte_Type Voltage_K;    // 电压转换系数
TwoByte_Type Current_K;    // 电流A 转换系数
TwoByte_Type Power_K;      // A 通道功率转换系数
TwoByte_Type LeakCur_K;    // 电流B 转换系数
TwoByte_Type Power_K_Leak; // B 通道功率转换系数
TwoByte_Type Energy_K;     // 电能脉冲计数，对应于1度电的脉冲计数

u32 initialEnery = 0; // 开机上次保存读数

typedef struct
{
    u8 addr;
    u8 data[3];
} BL0903_req_t;

// static BL0903_req_t config_req[] = {
//     {MODE, {0x00, 0x10, 0x00}},        // 报警功能开启50hz 400ms/
//     {TPS_CTRL, {0xff, 0xff, 0x00}},    // 开启A通道过流，漏电报警
//     {A_F_RMS_CTL, {0xE6, 0xF4, 0x00}}, // 短路40A:0x3A77  80A:0x74E6
//     {B_F_RMS_CTL, {0x62, 0x84, 0x00}}, // 漏电30mA
// };

/*******************************************************************************
 函 数 名： delay_nms
 功能描述： 延时nms
 入口参数： n:ms数
 出口参数： 无
********************************************************************************/
void delay_nms(u16 time)
{
    u16 i = 0;
    while (time--)
    {
        i = 12000; // 自己定义
        while (i--)
            ;
    }
}

//  SPI2发送
void BL_SPIReadData()
{
    // bl 读为两个字节 0X55+REG，返回为四个字节，因此需要发送无效FF
    u8 i = 0;
    u8 d = 0;
    for (i = 0; i < RnSend.Len; i++)
    {
        d = SPI2_ReadWriteByte(RnSend.Data[i]);
        // WPrint("@@@@@ send %d recv %d\r\n", RnSend.Data[i], d);
    }
    for (i = 0; i < RN_READ_DATA_LEN; i++)
    {
        d = SPI2_ReadWriteByte(0xff);
        // WPrint("@@@@@ send %d recv %d\r\n", RnSend.Data[i], d);
        RnRece.Data[i] = d;
        RnRece.Len++;
    }
}

// SPI读数据
void BL_Read(u8 wReg)
{
    memset(RnSend.Data, 0, sizeof(RnSend.Data)); // 清空发送缓存数组
    memset(RnRece.Data, 0, sizeof(RnRece.Data)); // 清空接收缓存数组
    RnSend.Data[0] = BL0939_Addr_R;              // 读命令
    RnSend.Data[1] = wReg;
    RnSend.Len = 2;
    // RnSend.HaveSenLen = 1;
    BL_SPIReadData();

    // return Block_Send();
}

// 校验数据是否正确
BOOL BLCheckSum(u8 reg, u8 *data)
{
    u8 i = 0;
    u8 checksum = 0;
    u8 addr = 0x55;
    checksum += addr;
    checksum += reg;
    for (i = 0; i < 3; i++)
        checksum += data[i];
    checksum = ~checksum;
    return (checksum == data[3]) ? TRUE : FALSE;
}

// 从芯片读数据
Error_code_t ReadData(u8 wreg, u32 *data)
{

    u8 temp_buf[4] = {0};
    u32 test = 0;
    BL_Read(wreg);
    memcpy(temp_buf, RnRece.Data, 4);
    if (BLCheckSum(wreg, temp_buf) == TRUE)
    {
        //  memcpy(data, temp_buf, len);
        test = temp_buf[0] * 256 * 256 + temp_buf[1] * 256 + temp_buf[2];
        memcpy(data, &test, 4);
        return RET_POW_SUC;
    }
    SPrint("$$$checksum failure\r\n");

    return RET_POW_FAL;
}

// 从芯片读数据
Error_code_t WriteData(u8 wreg, u8 *data)
{

    uint8_t CHKSum = 0;

    /*!< Send the byte */
    SPI2_WriteByte(BL0939_Addr_w);
    CHKSum = BL0939_Addr_w;
    SPI2_WriteByte(wreg);
    CHKSum = CHKSum + wreg;
    SPI2_WriteByte(data[0]);
    CHKSum = CHKSum + data[0];
    SPI2_WriteByte(data[1]);
    CHKSum = CHKSum + data[1];
    SPI2_WriteByte(data[2]);
    CHKSum = CHKSum + data[2];
    CHKSum = 0xFF - CHKSum;
    SPI2_WriteByte(CHKSum);
    /*!< Return the shifted data */
    //   return Data;

    return RET_POW_SUC;
}

// 读取芯片id
Error_code_t get_device_id()
{
    static u8 fail_count = 0;
    u32 id = 0;
    if ((ReadData(WA_CREEP, &id) == RET_POW_SUC) && (id == 0x0B || id == 0x39)) // 可能呗修改了
    {
        fail_count = 0;
        return RET_POW_SUC;
        // delay_nms(5);
    }
    else
    {
        // 读取失败，重复读取
        if (++fail_count >= 3)
        {
            fail_count = 0;
            return RET_POW_FAL;
        }
        return get_device_id();
    }
    // return RET_POW_SUC;
}

// 芯片初始化
Error_code_t Chip_Init(void)
{
    return ((get_device_id() == RET_POW_SUC) ? RET_POW_SUC : RET_POW_FAL); // 读取id检验通信是否成功
                                                                           // 读上电初始化时配置的用户写保护寄存器，用来判断是否发生过复位
    // ReadData(BL0939_Addr_R, USR_WRPROT);
    // if (BL0939_D_u8[2] != 0x55) // 写保护寄存器被清零，发生过复位，电参数寄存器清零
    // {
    //     BL0939_Elect.Fir_CFA_CNT = 0; // 上一次的CFA_CNT寄存器读数
    //     BL0939_Elect.Fir_CFB_CNT = 0; // 上一次的CFB_CNT寄存器读数
    //     BL0939_Init();                // 用户区参数重新装载
    // }
}

void BL0939_Init(void)
{
    u8 BL0939_D_u8[3];

    BL0939_D_u8[0] = 0x00;
    BL0939_D_u8[1] = 0x00;
    BL0939_D_u8[2] = 0x55;
    WriteData(USR_WRPROT, BL0939_D_u8); // USR_WRPROT			打开用户操作寄存器的写保护
    // 设置有功功率防潜寄存器，用于噪声功率切除，参考设计对应1瓦功率；有功功率寄存器1398以下的数据切除到0
    // 1398/3.0517578125/8≈57，WA_CREEP=0x39；
    BL0939_D_u8[0] = 0x00;
    BL0939_D_u8[1] = 0x00;
    BL0939_D_u8[2] = 0x39;
    WriteData(WA_CREEP, BL0939_D_u8);
#ifdef Leak_Mode_B
    // 600:1零序电流互感器，100欧负载电阻，30mA时5mV对应 有效值1372171
    // 20mA时对应有效值 924163，快速有效值约660210
    // FAST_RMS=1372171*0.72,    判断阈值约 FAST_RMS/0x200=0x789
    BL0939_D_u8[0] = 0x00;
    BL0939_D_u8[1] = 0x07;
    BL0939_D_u8[2] = 0x89;
    BL0939_WriteData(BL0939_Addr_w, Addr_IB_FAST_RMS_CTRL); // B_FAST_RMS_CTRL   设置B通道作为漏电检测的阈值
    // BL0939_ReadData(BL0939_Addr_R,Addr_IB_FAST_RMS_CTRL)	;
#endif
}

u32 ReadSaveEngery()
{
    ReadFlash(ENGERY_SAVE_ADDRESS, &initialEnery, 1);
    return initialEnery;
}

// 初始化芯片，本次采用SPI2 进行读写
u8 BL_Init(void)
{
    SPI2_Init();
    if (Chip_Init() == RET_POW_FAL) // 芯片初始化
    {
        SPrint("**BL chipset initial failure**\r\n");
        return 0;
    }
    ReadSaveEngery();
    BL0939_Init();
    BL0939_Parameter_Init();

    WPrint("###initial data %x\r\n", initialEnery);

    // if (set_powercheck_ic() == RET_POW_FAL)
    // {
    //      SPrint("**BL chipset initial failure: powcheck**\r\n");
    // }
    return 1;
}

/**********************************************
 *Function:			BL0939_ReadEData
 *Description:		BL0939读电参数函数
 *Parameter:
 *Return:				转换为实际电参数数据，放到对应发送数组中
 *Author:
 *Data:					2018.08.30
 ***********************************************/
Elect_StructDef BL0939_ReadEData(void)
{
    u32 tmp_D;
    bool sign_A_WATT = 0; // A通道有功功率的符号位，0表示正功，1表示负功
    bool sign_B_WATT = 0; // B通道有功功率的符号位，0表示正功，1表示负功
    u32 tmp_V;
    bool sign_A_Engery = 0; // A通道有功功率的符号位，0表示正功，1表示负功
    bool sign_B_Engery = 0; // B通道有功功率的符号位，0表示正功，1表示负功


    ReadData(IA_RMS, &tmp_D);                         // IA_RMS
    tmp_D = (tmp_D * 1.218 * 100 / 324004) * 2 / 3.3; // 保留两位小数
    BL0939_Elect.Current_Value_A = tmp_D;
    delay_nms(2);

    ReadData(IB_RMS, &tmp_D);             //   IB_RMS
    BL0939_Elect.Current_Value_B = tmp_D; // b 通道为啥不处理？？？
    delay_nms(2);

    ReadData(V_RMS, &tmp_D); // V_RMS

    tmp_D = 10 * (tmp_D * 1.218 / 79931) * 100 / 24.9;  //xxx.X *10 保留一位
    BL0939_Elect.Voltage_Value = tmp_D;
    delay_nms(2);

    ReadData(A_WATT, &tmp_D); // A_WATT

    if (tmp_D > 0x7FFFFF) // 有功功率寄存器Bit[23]为符号位，如果为负功，补码转换
    {
        tmp_D = 0x1000000 - tmp_D;
        sign_A_WATT = 1;
    }
    tmp_D = (tmp_D / 10000) * 8.9245;
    BL0939_Elect.Power_Value_A = tmp_D;
    delay_nms(2);

    ReadData(B_WATT, &tmp_D); // B_WATT
    if (tmp_D > 0x7FFFFF)     // 有功功率寄存器Bit[23]为符号位，如果为负功，补码转换
    {
        tmp_D = 0x1000000 - tmp_D;
        sign_B_WATT = 1;
    }
    tmp_D = (tmp_D / 10000) * 8.9245;
    BL0939_Elect.Power_Value_B = tmp_D;
    delay_nms(2);

    ReadData(TPS1, &tmp_D); // TPS1
    tmp_D = (tmp_D * 5 - 320) * 170 / 480 - 450;
    BL0939_Elect.v_TPS1 = tmp_D;
    delay_nms(2);

    ReadData(TPS2, &tmp_D); // TPS2
    BL0939_Elect.v_TPS2 = tmp_D;
    delay_nms(2);

    // 注意如果有功功率是负功，电能累积是从0x000000向下递减
    // 注意如果有功功率是正功，电能累积是从0x000000向上递增
    ReadData(CFA_CNT, &tmp_D); // CFA_CNT WATTHR
    // 有功功率为正功时的电能累积处理
    // Energy_kwh_A、Energy_kwh_B低位为0.001度/LSB，脉冲计数放大1000倍去整除电能常数得到的就是0.001度电的倍数
    // Mid_CFA_CNT只保存1度电的脉冲计数*1000的余数
    WPrint("tmp_D: %d  Fir_CFA_CN: %d \r\n", tmp_D, BL0939_Elect.Fir_CFA_CNT);
    // 初始启动时候为0，要复制一下
    if (BL0939_Elect.Fir_CFA_CNT == 0)
    {
        BL0939_Elect.Fir_CFA_CNT = tmp_D;
        BL0939_Elect.Mid_CFA_CNT = tmp_D;
        BL0939_Elect.Energy_kwh_A = 0;
    }

    if (tmp_D >= BL0939_Elect.Fir_CFA_CNT) // 当前脉冲数大于前次脉冲数
    {
        if (tmp_D - BL0939_Elect.Fir_CFA_CNT < 100) // 定时间隔内的电能脉冲个数小于等于最大电流时的电能累积个数，正常信号
        {
            BL0939_Elect.Mid_CFA_CNT = BL0939_Elect.Mid_CFA_CNT + (tmp_D - BL0939_Elect.Fir_CFA_CNT);
            BL0939_Elect.Fir_CFA_CNT = tmp_D;
        }
    }
    else // 当前脉冲数小于前次脉冲数，判断是否是累积溢出，翻零重计
    {
        if (BL0939_Elect.Fir_CFA_CNT - tmp_D > 100)
        {
            BL0939_Elect.Mid_CFA_CNT = BL0939_Elect.Mid_CFA_CNT + (tmp_D + (0xFFFFFF - BL0939_Elect.Fir_CFA_CNT));
            BL0939_Elect.Fir_CFA_CNT = tmp_D;
            sign_A_Engery = 1;

        }
    }

    BL0939_Elect.Energy_kwh_A = BL0939_Elect.Energy_kwh_A + (BL0939_Elect.Mid_CFA_CNT / Energy_K.uInt);

    // 实际用电量=Energy_kwh_A/1000 度电
    BL0939_Elect.Mid_CFA_CNT = ((BL0939_Elect.Mid_CFA_CNT) % Energy_K.uInt);

    tmp_V = BL0939_Elect.Energy_kwh_A * 100 + BL0939_Elect.Mid_CFA_CNT * 100 / Energy_K.uInt;

    // 判断是否需要保存,如果翻转，保存到FLASH中,不知道什么时候清零，暂时不需要
    if (sign_A_Engery == 1 || initialEnery == 0xffffffff)
    {
        WriteFlash(ENGERY_SAVE_ADDRESS, &tmp_V, sizeof(tmp_V));
        Energy_kwh_A_save = tmp_V;
    }

    delay_nms(2);

    ReadData(CFB_CNT, &tmp_D); // CFB_CNT WATTHR
    // 有功功率为正功时的电能累积处理
    if (tmp_D >= BL0939_Elect.Fir_CFB_CNT)
    {
        if (tmp_D - BL0939_Elect.Fir_CFB_CNT < 100)
        {
            BL0939_Elect.Mid_CFB_CNT = BL0939_Elect.Mid_CFB_CNT + (tmp_D - BL0939_Elect.Fir_CFB_CNT);
            BL0939_Elect.Fir_CFB_CNT = tmp_D;
        }
    }
    else
    {
        if (BL0939_Elect.Fir_CFB_CNT - tmp_D > 100)
        {
            BL0939_Elect.Mid_CFB_CNT = BL0939_Elect.Mid_CFB_CNT + (tmp_D + (0xFFFFFF - BL0939_Elect.Fir_CFB_CNT));
            BL0939_Elect.Fir_CFB_CNT = tmp_D;
        }
    }

    BL0939_Elect.Energy_kwh_B = BL0939_Elect.Energy_kwh_B + (BL0939_Elect.Mid_CFB_CNT / Energy_K.uInt);
    BL0939_Elect.Mid_CFB_CNT = BL0939_Elect.Mid_CFB_CNT % Energy_K.uInt;
    // 消除告警先，不知道这个反转标记干啥，先放着
    sign_A_WATT = sign_A_WATT;
    sign_B_WATT = sign_B_WATT;
    sign_B_Engery= sign_B_Engery;
    return BL0939_Elect;
}
/*********************************
电量参数初始化
装载根据外围硬件初始化转换系数电参数转换

*********************************/
void BL0939_Parameter_Init(void)
{
    
    // 演示程序不带电量存储功能，
    BL0939_Elect.Energy_kwh_B = 0; // 电流B 通道的实际用电量，千瓦小时 XXXXXX.XXX；如果有存储，从存储装入
    BL0939_Elect.Energy_kwh_A = 0; // 电流A 通道的实际用电量，千瓦小时 XXXXXX.XXX；如果有存储，从存储装入
    BL0939_Elect.Fir_CFA_CNT = 0;  // 上一次的CFA_CNT寄存器读数
    BL0939_Elect.Fir_CFB_CNT = 0;  // 上一次的CFB_CNT寄存器读数
    BL0939_Elect.Mid_CFA_CNT = 0;  // A 通道电能累积换算的中间变量
    BL0939_Elect.Mid_CFB_CNT = 0;
    // 将上次的放入计费值
    BL0939_Elect.Energy_kwh_A = initialEnery/100 ;
    BL0939_Elect.Energy_kwh_A_xiaoshu = initialEnery%100 ;
    // 根据外围器件参数装载转换系数
    // 出厂校准芯片，增益控制1%以内，外围器件精度控制1%以内，采用同一系数，
    // 2019.06.14 电流采用1毫欧电阻采样，电压采用390K*5+0.5K(两个1K并联)进行分压，实际测试发现电阻存在偏差，进行微调
    // 电压通道电容采用两颗33nF并联，对应评估板BL0939_SSOP20L_EVA V2
    /*
        Power_K.uInt=7057;						// 4046*1毫欧*1K*1000/(1.218*1.218)/(390K*5+1K)=13979
        Current_K.uInt=26787; 				// 324004*1毫欧/1.218=266013
        Voltage_K.uInt=16866; 				// 79931*1K*1000/1.218/(390K*5+1K)=33636
        LeakCur_K.uInt=26787;
        Power_K_Leak.uInt=7057;
        Energy_K.uInt=6057; 					//	 3600000*Power_K/16384/256=11998
        */
    // 2019.08.29 电流采用1毫欧电阻采样,立创购买美隆1%精度，电压采用390K*5+0.5K(两个1K并联)进行分压，实际测试发现电阻存在偏差，进行微调
    // 电压通道电容采用两颗33nF并联，对应评估板BL0939_SOP16_EVA1
    /*	Power_K.uInt=7068;						// 4046*1毫欧*1K*1000/(1.218*1.218)/(390K*5+1K)=13979
        Current_K.uInt=26787; 				// 324004*1毫欧/1.218=266013
        Voltage_K.uInt=16892; 				// 79931*1K*1000/1.218/(390K*5+1K)=33636
        LeakCur_K.uInt=26787;
        Power_K_Leak.uInt=7068;
        Energy_K.uInt=6067; 					//	 3600000*Power_K/16384/256=11998 */
    // 2020.02.10	 电压采用390K+510欧，电压通道电容采用68nF并联，美隆1%精度电阻

    Power_K.uInt = 7198;    // 4046*1毫欧*0.51K*1000/(1.218*1.218)/(390K*5+0.51K)=7131
    Current_K.uInt = 26787; // 324004*1毫欧/1.218=266013
    Voltage_K.uInt = 17203; // 79931*0.51K*1000/1.218/(390K*5+0.51K)=17159
    LeakCur_K.uInt = 26787;
    Power_K_Leak.uInt = 7198;
    Energy_K.uInt = 9617; //	 3600000*Power_K/16384/256=6120 	  */
}

u32 getCurrentEnergy_kwh_A()
{
    // 放大100倍 XXX.XX
    // return initialEnery + BL0939_Elect.Energy_kwh_A * 100 + BL0939_Elect.Mid_CFA_CNT * 100  / Energy_K.uInt;
    return BL0939_Elect.Energy_kwh_A * 100 + BL0939_Elect.Energy_kwh_A_xiaoshu  + BL0939_Elect.Mid_CFA_CNT * 100 / Energy_K.uInt;
}


u32 getCurrent_IA()
{
    // 放大100倍 XXX.Xx
    // return initialEnery + BL0939_Elect.Energy_kwh_A * 100 + BL0939_Elect.Mid_CFA_CNT * 100  / Energy_K.uInt;
    return BL0939_Elect.Current_Value_A;
}


u32 getCurrent_V()
{
    // 放大10倍 XXX.X
    // return initialEnery + BL0939_Elect.Energy_kwh_A * 100 + BL0939_Elect.Mid_CFA_CNT * 100  / Energy_K.uInt;
    return BL0939_Elect.Voltage_Value;
}


